import numpy as np
from fplugins import *
from fstatistics import *
    
class StatisticsNotSupportedError(Exception): pass

ERROR_NO_EV = "未加载EV数据"
ERROR_NO_CSPK = "未加载充电站数据"
ERROR_NO_GEN = "未加载发电机数据"

class ReadOnlyStatistics(StaReader):
    def has_CS(self)->bool: return self.__cs_head is not None
    def has_EV(self)->bool: return FILE_EV in self
    def has_GEN(self)->bool: return FILE_GEN in self
    def has_BUS(self)->bool: return FILE_BUS in self
    
    def __init__(self,path:str,time_line:Optional[list[int]]=None):
        super().__init__(path,time_line)
        def __trans(x:str):
            p = x.rfind("#")
            if p>=0: return x[:p]
            return x
            
        if FILE_CS not in self:
            self.__cs_head = None
        else:
            self.__cs_head = list(set(__trans(x) for x in self.GetTable(FILE_CS).head))
            self.__cs_head.sort()
        if FILE_EV not in self:
            self.__ev_head = None
        else:
            self.__ev_head = list(set(__trans(x) for x in self.GetTable(FILE_EV).head))
            self.__ev_head.sort()
        if FILE_GEN not in self:
            self.__gen_head = None
        else:
            self.__gen_head = list(set(__trans(x) for x in self.GetTable(FILE_GEN).head))
            for itm in GEN_TOT_ATTRIB:
                if itm in self.__gen_head:
                    self.__gen_head.remove(itm)
            self.__gen_head.sort()
        if FILE_BUS not in self:
            self.__bus_head = None
        else:
            self.__bus_head = list(set(__trans(x) for x in self.GetTable(FILE_BUS).head))
            for itm in BUS_TOT_ATTRIB:
                if itm in self.__bus_head:
                    self.__bus_head.remove(itm)
            self.__bus_head.sort()
        
    @property
    def CS_head(self)->list[str]:
        assert self.__cs_head is not None
        return self.__cs_head

    @property
    def veh_head(self)->list[str]:
        assert self.__ev_head is not None
        return self.__ev_head
    
    @property
    def gen_head(self)->list[str]:
        assert self.__gen_head is not None
        return self.__gen_head
    
    @property
    def bus_head(self)->list[str]:
        assert self.__bus_head is not None
        return self.__bus_head
    
    def CS_charge_load_of(self,cs:str)->np.ndarray:
        '''充电功率(不考虑返送功率)'''
        return self.GetColumn(FILE_CS,cs+"#c")
    
    def CS_v2g_load_of(self,cs:str)->np.ndarray:
        '''V2G实际返送功率'''
        return self.GetColumn(FILE_CS,cs+"#d")
    
    def CS_v2g_cap_of(self,cs:str)->np.ndarray:
        '''V2G最大返送功率'''
        return self.GetColumn(FILE_CS,cs+"#v2g")
    
    def CS_net_load_of(self,cs:str)->np.ndarray:
        '''净充电功率'''
        if cs.startswith("CS"): return self.CS_charge_load_of(cs)
        return self.CS_charge_load_of(cs) - self.CS_v2g_load_of(cs)
    
    def CS_count_of(self,cs:str)->np.ndarray:
        '''充电站车辆数'''
        return self.GetColumn(FILE_CS,cs+"#cnt")

    def CS_pricebuy_of(self,cs:str)->np.ndarray:
        '''购电价格'''
        return self.GetColumn(FILE_CS,cs+"#pb")
    
    def CS_pricesell_of(self,cs:str)->np.ndarray:
        '''售电价格'''
        return self.GetColumn(FILE_CS,cs+"#ps")
    
    def EV_attrib_of(self,veh:str,attrib:str)->np.ndarray: 
        '''EV信息'''
        assert attrib in EV_ATTRIB, f"EV属性错误: {attrib}"
        return self.GetColumn(FILE_EV,veh+"#"+attrib)
    
    def EV_net_cost_of(self,veh:str)->np.ndarray: 
        '''EV净成本'''
        return self.GetColumn(FILE_EV,veh+"#cost")-self.GetColumn(FILE_EV,veh+"#earn")
    
    def EV_loc_of(self,veh:str)->tuple[np.ndarray,np.ndarray]:
        '''EV坐标位置'''
        data=np.stack([self.GetColumn(FILE_EV,veh+"#x"),self.GetColumn(FILE_EV,veh+"#y"),self.GetColumn(FILE_EV,veh+"#status")],axis=1)
        cond=data[:,2]<=1e-4
        return data[cond,0],data[cond,1]
    
    def G_attrib_of(self,g:str,attrib:str)->np.ndarray: 
        '''发电机信息'''
        assert attrib in GEN_ATTRIB
        return self.GetColumn(FILE_GEN,g+"#"+attrib)
    
    def G_total(self,attrib:str)->np.ndarray:
        '''总发电数据'''
        assert attrib in GEN_TOT_ATTRIB
        return self.GetColumn(FILE_GEN,attrib)
    
    def bus_attrib_of(self,b:str,attrib:str)->np.ndarray: 
        '''母线信息'''
        assert attrib in BUS_ATTRIB
        return self.GetColumn(FILE_BUS,b+"#"+attrib)
    
    def bus_total(self,attrib:str)->np.ndarray:
        '''总母线数据'''
        assert attrib in BUS_TOT_ATTRIB
        return self.GetColumn(FILE_BUS,attrib)